home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / editor / aspell20.zip / ORPHCHK.PAS < prev    next >
Pascal/Delphi Source File  |  1996-01-19  |  17KB  |  339 lines

  1. unit Orphchk;
  2.  
  3. interface
  4.  
  5. { IMPORTANT: This component REQUIRES that you have Turbo Power's Orpheus
  6.   components installed.  It makes use of the Orpheus TOVCCustomEditor so
  7.   you can spell check the following Orpheus editor types with the OrphCheck
  8.   method: TOvcCustomEditor, TOvcEditor, TOvcCustomTextEditor, TOvcTextFileEditor
  9.   and TOvcdbEditor.
  10.   None of Turbo Power's units, components or source is included with this package
  11.   as that would be illegal redistribution of their product.  However, if you
  12.   have a need for a large editor (files up to 16 megabytes) to replace TMemo
  13.   I would highly recommend you purchase Turbo Power's Orpheus package.  Besides
  14.   the large editors it also provides a large number of useful and powerful
  15.   components for Delphi such as:
  16.  
  17.      Large virtual list boxes, numerous data entry types, array editors,
  18.      Table components, spinners, rotated labels, timers and much more.
  19.  
  20.   Turbo Power Software can be reached at: 1-800-333-4160                    }
  21.  
  22.  
  23. uses
  24.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  25.   Forms, Dialogs, StdCtrls, SugDialg, OvcBase, OvcData, OvcEdit;
  26.                                     { ^ Orpheus units needed  ^}
  27.  
  28. type SuggestionType = (stNoSuggest, stCloseMatch, stPhoneme);
  29.  
  30. type
  31.   TOrphSpell = class(TComponent)
  32.   private
  33.     { Private declarations }
  34.     FSuggestType         : SuggestionType;  { Holds the default initial suggestion type }
  35.     FDictionaryMain      : string;          { Holds the name of the main dictionary file }
  36.     FDictionaryUser      : string;          { Holds the name of the user's custom dictionary file }
  37.     FSuggestMax          : byte;            { Holds the maximum number of suggestions to return }
  38.     UserDictID           : integer;         { Holds the ID number ofhte open user dictionary }
  39.     FLeaveDictionaryOpen : boolean;         { Should we leave the dictionary files open? }
  40.     FDictionaryOpen      : boolean;          { Is the dictionary open? }
  41.   protected
  42.     { Protected declarations }
  43.     DictDataPtr: pointer;                  { Pointer to internal dictionary data }
  44.     SuggestDlg : TSugDialog;               { The dialog box for this component }
  45.     StartWord  : string;                   { Temporary place to store the word being tested }
  46.     IgnoreList : TStringList;              { List of words to ignore }
  47.     ReplaceList   : TStringList;           { Replacement word list }
  48.     AlternateList : TStringList;           { Replacement word alternate word list }
  49.     procedure BaseCheckOrph(var TheEditor : TOvcCustomEditor;
  50.                             StartLine : longint; StartCol : integer;
  51.                             EndLine   : longint; EndCol   : integer);
  52.   public
  53.     { Public declarations }
  54.     UserDictionaryOpen : boolean;                 { Record if the custom user dictionary was opened ok }
  55.     constructor Create(AOwner : TComponent); override;  { Standard create method }
  56.     procedure Free;                        { Standard free method }
  57.     procedure SetMaximumSuggestions(Max : byte);      { Method to set the maximum number of suggestions }
  58.     property DictionaryOpen : boolean read FDictionaryOpen;
  59.  published
  60.     { Published declarations }
  61.     procedure CheckOrph(TheEditor : TOvcCustomEditor);   { Main method, check the spelling of a Orpheus Editor types }
  62.     procedure CheckOrphSelection(TheEditor : TOvcCustomEditor); { Alternate method to check only selected text }
  63.     procedure ClearLists;                                { Method to clear the ignore/replace lists }
  64.     property SuggestType : SuggestionType read FSuggestType write FSuggestType default stCloseMatch;
  65.        { Get/Set the initial suggestion type }
  66.     property DictionaryMain : string read FDictionaryMain write FDictionaryMain;
  67.        { Get/Set the name of the main dictionary file }
  68.     property DictionaryUser : string read FDictionaryUser write FDictionaryUser;
  69.        { Get/Set the name of the user dictionary file }
  70.     property MaxSuggestions : byte read FSuggestMax write SetMaximumSuggestions default 10;
  71.        { Get/Set the maximum number of suggestions }
  72.     property LeaveDictionariesOpen : boolean read FLeaveDictionaryOpen write FLeaveDictionaryOpen default TRUE;
  73.        { Get/Set whether the dictionary should be opened/closed after each call }
  74.   end;
  75.  
  76.  
  77. procedure Register;
  78.  
  79. implementation
  80.  
  81. uses BaseASpl;
  82.  
  83.  
  84. procedure Register;  { Standard component registration procedure }
  85. begin
  86.   RegisterComponents('Samples', [TOrphSpell]);
  87. end;
  88.  
  89.  
  90. constructor TOrphSpell.Create(AOwner : TComponent);
  91. { Standard create method }
  92. begin
  93.   inherited Create(AOwner);           { Make sure the base component to made }
  94.   FSuggestType := stCloseMatch;       { Set the default values }
  95.   FDictionaryMain := 'acrop.dct';
  96.   FDictionaryUser := 'custom.dct';
  97.   FLeaveDictionaryOpen := TRUE;
  98.   FDictionaryOpen  := FALSE;
  99.   UserDictionaryOpen := FALSE;
  100.   FSuggestMax     := 10;
  101.   IgnoreList := TStringList.Create;   { Create the list of ignored words }
  102.   IgnoreList.Clear;                   { And set it to the way it is needed to be }
  103.   IgnoreList.Sorted := TRUE;
  104.   ReplaceList := TStringList.Create;   { Create the list of words to replace }
  105.   ReplaceList.Clear;                   { And set it up }
  106.   ReplaceList.Sorted := FALSE;
  107.   AlternateList := TStringList.Create; { Create the list of words to replace with }
  108.   AlternateList.Clear;                 { And set it up }
  109.   AlternateList.Sorted := FALSE;
  110.   InitDictionaryData(DictDataPtr);        { Create the internal dictionary data }
  111.   SuggestDlg := TSugDialog.Create(Self);  { Create the dialog box }
  112.   SuggestDlg.DictDataPtr := DictDataPtr;  { And let it know the internal data address }
  113. end;
  114.  
  115. procedure TOrphSpell.Free;
  116. { Standard free method }
  117. begin
  118.   if FDictionaryOpen then
  119.     BaseASpl.CloseDictionaries(DictDataPtr);
  120.   IgnoreList.Free;     { Get rid of the ignore list }
  121.   ReplaceList.Free;    { Get rid of the replacement list }
  122.   AlternateList.Free;  { Get rid of the replacement word list }
  123.   SuggestDlg.Free;     { Get rid of the suggestion dialog box }
  124.   inherited Free;      { and then the base component }
  125. end;
  126.  
  127. procedure TOrphSpell.SetMaximumSuggestions(Max : byte);
  128. { Set the maximum number of suggestions to return }
  129. { The test of check to see if it is over thirty is really not needed since the }
  130. { low level routines in BaseASpl will force any value over 30 to 30 anyway     }
  131. begin
  132.   if Max > 30 then      { Make sure it isn't over 30 }
  133.     Max := 30;
  134.   FSuggestMax := Max;   { And store the value }
  135. end;
  136.  
  137. procedure TOrphSpell.ClearLists;
  138. begin
  139.   IgnoreList.Clear;                    { Clear the ignore list }
  140.   IgnoreList.Sorted := TRUE;
  141.   ReplaceList.Clear;                   { Clear the list of words to replace }
  142.   ReplaceList.Sorted := FALSE;
  143.   AlternateList.Clear;                 { Clear the list of words to do the replacing with }
  144.   AlternateList.Sorted := FALSE;
  145. end;
  146.  
  147. procedure TOrphSpell.BaseCheckOrph(var TheEditor : TOvcCustomEditor;
  148.                                        StartLine : longint; StartCol : integer;
  149.                                        EndLine   : longint; EndCol   : integer);
  150. { The main method for this component.  Test the spelling of the text in the passed memo }
  151. var Done       : boolean;        { Loop control }
  152.     OldHide    : boolean;        { Storage for the original state of the HideSelection property }
  153.     Changed    : boolean;        { Was anything in the memo changed? }
  154.     EmptyList  : TStringList;    { Empty list in case user dictionary need to be made }
  155.     TheResult  : integer;        { Temporary storage for ShowModal return value }
  156.     Start      : integer;        { Start of the word }
  157.     WordEnd    : integer;        { End of the word }
  158.     CCol       : integer;        { Current column being checked }
  159.     CLine      : longint;        { Current line being checked }
  160.   function StripWord(L : STRING; VAR SCol : INTEGER; var EndCol : integer) : STRING;
  161.   VAR S, T   : STRING;
  162.   BEGIN
  163.     S := Copy(L,SCol, 255);   { Get just the end of the string }
  164.     EndCol := SCol;           { Set the end of the word to the start }
  165.     WHILE (S<> '') AND (NOT (S[1] IN ['A'..'Z','a'..'z',#138,#140,#159,   { Skip any non-letters }
  166.                                       #192..#214,#216..#223,#240,
  167.                                       #154,#156,#224..#239,
  168.                                       #241..#246,#248..#255])) DO
  169.       BEGIN
  170.         Delete(S,1,1);
  171.         Inc(EndCol);
  172.         Inc(SCol);
  173.       END;
  174.     IF S = '' THEN           { No non-letter left on line, so no word found }
  175.       BEGIN
  176.         StripWord := '';
  177.         Exit;
  178.       END;
  179.     T := '';      { Clear out a string to hold the word as be build it }
  180.     WHILE (S <> '') AND (S[1] IN ['A'..'Z','a'..'z',#138,#140,#159,   { Only add letters and "'" }
  181.                                   #192..#214,#216..#223,#240,
  182.                                   #154,#156,#224..#239,
  183.                                   #241..#246,#248..#255,'''']) DO
  184.       BEGIN
  185.         T := T + S[1];
  186.         Delete(S,1,1);
  187.         Inc(EndCol);
  188.       END;
  189.     StripWord := T;     { Return the word we found }
  190.   END;
  191.   function GetNextWord : STRING;
  192.   BEGIN
  193.     GetNextWord := '';
  194.     WITH TheEditor DO
  195.       BEGIN
  196.         IF CCol > LineLength[CLine] THEN
  197.           BEGIN
  198.             Inc(CLine);
  199.             CCol := 1;
  200.           END;
  201.         IF CLine > LineCount THEN  { Passed the end of the editor get out of here }
  202.           Exit;
  203.         IF (CLine = LineCount) AND (CCol >= LineLength[CLine]) THEN    { Ditto }
  204.           Exit;
  205.         GetNextWord := StripWord(Lines[CLine], CCol, WordEnd);  { Get the text of the word }
  206.         Start := CCol;                      { Save where this word started }
  207.       END;
  208.   END;
  209. begin
  210.   try
  211.   Changed := FALSE;  { Nothing has been changed yet. }
  212.   OldHide := TheEditor.HideSelection;     { Save the old HideSelection property }
  213.   TheEditor.HideSelection := FALSE;        { and make sure selections are shown }
  214.   SuggestDlg.MaxSuggest := FSuggestMax;  { Set the maximum number of suggestions }
  215.   if not FDictionaryOpen then  { Check to see if the dictionary is already open }
  216.     begin
  217.       FDictionaryOpen := BaseASpl.OpenDictionary(DictDataPtr, FDictionaryMain);  { Open the dictionaries }
  218.       UserDictID := BaseASpl.OpenUserDictionary(DictDataPtr, FDictionaryUser);  { And record if they actually opened }
  219.       if UserDictID < 0 then        { Didn't open so try to make one }
  220.         begin
  221.           EmptyList := TStringList.Create;   { Create and clear to make an empty list }
  222.           EmptyList.Clear;
  223.           UserDictID := BaseASpl.BuildUserDictionary(DictDataPtr, FDictionaryUser, EmptyList);  { Build dictionary }
  224.           EmptyList.Free;  { Free the empty list }
  225.         end;
  226.       UserDictionaryOpen := UserDictID > 0;  { Check to see if dictionary was opened/made }
  227.     end;
  228.   with SuggestDlg do  { The suggestion dialog is used a lot so make it easily accessible }
  229.     begin
  230.       CCol  := StartCol;   { Set to beginning of section to spell check }
  231.       CLine := StartLine;
  232.       Done := FALSE;            { Assume we aren't done }
  233.       repeat
  234.         StartWord := GetNextWord;       { Get the next word in the memo }
  235.         IF not BaseASpl.GoodWord(DictDataPtr, StartWord) THEN  { Is the word in the dictionaries? }
  236.           if IgnoreList.IndexOf(Uppercase(StartWord)) = -1 then  { No, is it in the ignore list? }
  237.             begin  { Word not found and not ignored }
  238.               TheEditor.SetSelection(CLine, Start, CLine, WordEnd, TRUE);
  239.               WordEdit.Text := StartWord;    { Setup the Suggestion dialog }
  240.               NotWord.Text := StartWord;     { Setup the Word we are checking }
  241.               ActiveControl := BtnIgnore;    { Make the Ignore Button active }
  242.               if ReplaceList.IndexOf(StartWord) = -1 then  { In the replacement list? }
  243.                 begin
  244.                   case FSuggestType of           { Build an inital list of suggestions }
  245.                     stCloseMatch : SuggestList.Items := BaseASpl.SuggestCloseMatch(DictDataPtr, StartWord, FSuggestMax);
  246.                     stPhoneme    : SuggestList.Items := BaseASpl.SuggestPhoneme(DictDataPtr, StartWord, FSuggestMax);
  247.                     stNoSuggest  : SuggestList.Clear;
  248.                   end;
  249.                   TheResult := ShowModal;  { Show the dialog box }
  250.                end
  251.               else
  252.                 begin
  253.                   TheResult := 101;  { Fake Replace Button being pressed }
  254.                   WordEdit.Text := AlternateList.Strings[ReplaceList.IndexOf(StartWord)]; { And get the replacement word }
  255.                 end;
  256.                case TheResult of   { Display the suggestion dialog }
  257.                 100 : Done := TRUE;                            { Cancel - end the spell checking }
  258.                 101,
  259.                 105 : begin
  260.                         { Replace - replace the word with the correction }
  261.                         TheEditor.Replace(StartWord, WordEdit.Text, [soReplace, soSelText]);
  262.                         Changed := TRUE;
  263.                         { Reset the end of word counter to reflect possible difference in word lengths }
  264.                         WordEnd := WordEnd + (Length(WordEdit.Text) - Length(StartWord));
  265.                         if CLine = EndLine then  { If this is the last line to test reset the ending column }
  266.                           EndCol := EndCol + (Length(WordEdit.Text) - Length(StartWord));
  267.                         if TheResult = 105 then { Replace all occurences }
  268.                           begin
  269.                             ReplaceList.Add(StartWord);
  270.                             AlternateList.Add(WordEdit.Text);
  271.                           end;
  272.                       end;
  273.                      { Add - the questioned word to the user dictionary }
  274.                 102 : BaseASpl.AddWord(DictDataPtr, StartWord, UserDictID);
  275.                 103 : ; { Ignore just this occurence - Dont' do anything }
  276.                      { Ignore All occurences - add the questioned word to the ignore list }
  277.                 104 : IgnoreList.Add(Uppercase(StartWord));
  278.               end;
  279.             end;
  280.         CCol := WordEnd+1;  { Move to one character after the end of the current word }
  281.       until Done or ((CLine >= EndLine) and (CCol >= EndCol));
  282.      { Canceled or end of the editor is reached }
  283.     end;
  284.   finally
  285.     if not FLeaveDictionaryOpen then  { Check if the dictionaries should be closed }
  286.       begin
  287.         BaseASpl.CloseDictionaries(DictDataPtr);       { Close the dictionaries  }
  288.         FDictionaryOpen := FALSE;          { Mark them as not opened }
  289.         UserDictionaryOpen := FALSE;
  290.       end;
  291.     TheEditor.HideSelection := OldHide; { Restore the HideSelection property of the memo }
  292.     if not Changed then    { Let the user know something actually happened }
  293.       MessageDlg('No changes made', mtInformation, [mbOK], -1)
  294.     else
  295.       MessageDlg('Checking complete', mtInformation, [mbOK], -1);
  296.   end;
  297. end;
  298.  
  299. procedure TOrphSpell.CheckOrph(TheEditor : TOvcCustomEditor);
  300. begin
  301.   { Call the base function to check the entire Editor }
  302.   BaseCheckOrph(TheEditor, 1,1, TheEditor.LineCount, TheEditor.LineLength[TheEditor.LineCount]);
  303. end;
  304.  
  305. procedure TOrphSpell.CheckOrphSelection(TheEditor : TOvcCustomEditor);
  306. var StartLine, EndLine : longint;
  307.     StartCol, EndCol   : integer;
  308.     S                  : string;
  309. begin
  310.   { If nothing is selected then just exit since there is nothing to check }
  311.   if not TheEditor.GetSelection(StartLine, StartCol, EndLine, EndCol) then
  312.     exit;
  313.  { Scan backward to make sure we're at the beginning of a word }
  314.   S := TheEditor.Lines[StartLine];
  315.   WHILE (StartCol > 0) AND (S[StartCol] IN ['A'..'Z','a'..'z',#138,#140,#159,
  316.                                             #192..#214,#216..#223,#240,
  317.                                             #154,#156,#224..#239,
  318.                                             #241..#246,#248..#255]) DO
  319.     Dec(StartCol);
  320.   IF StartCol = 0 THEN
  321.     StartCol := 1;
  322.  { Scan forward to make sure we have a whole word at the end of the selection }
  323.   S := TheEditor.Lines[EndLine];
  324.   Dec(EndCol);
  325.   if EndCol < 0 then
  326.     EndCol := 0;
  327.   while (EndCol < Length(S)) and (S[EndCol] in ['A'..'Z','a'..'z',#138,#140,#159,
  328.                                                 #192..#214,#216..#223,#240,
  329.                                                 #154,#156,#224..#239,
  330.                                                 #241..#246,#248..#255]) DO
  331.     Inc(EndCol);
  332.   if EndCol > Length(S) then
  333.     EndCol := Length(S);
  334.   BaseCheckOrph(TheEditor, StartLine,StartCol, EndLine,EndCol);
  335. end;
  336.  
  337.  
  338. end.
  339.